#!/rusr/bin/env python
# coding=UTF8

# Finished Features:
#    Login
#    Show resources/buildings status 
#    Upgrade resource fields (Balanced upgrading strategy)
#    Check constructing status
#    Simulate WinXP + IE6 
#    Enabled proxy
#    Multiple account support
#    Read account from configure file
#    Auto assign proxy
#    Robust connection error handler
#    Auto register
#    HTML output
#    Connection timeout handle
#    Error handle
#    Ratio based upgrading strategy
#    Build town buildings
#    Keeping COOKIES file for each account, so as to skip login step
#    Scan neighbouring players status
#    Save account info in database
#    Map scan
#    Save robot status in database
#    Anti-MultiHunter (Experimental)
#    Constructing/Building resource fields and building simuteniously
#
# TODOs: 
#    Multi Viliage
#    Time schedule
#    Make sure each account looped
#    Parse reports detail
#    Save reports and messages in database
#    Multithread - Pending

import urllib, urlparse
import pycurl
import random
import cStringIO
import os, re, sys
import time, datetime
import myproxy  # MyProxy module
import smtplib, base64
import logging

# 邮件服务器地址
mailserver = "smtp.126.com"
# 邮件用户名
username = "aryaky@126.com"
#username = "travian_s_6@126.com"
# 密码
password = "704510"
#password = "ufouho704510"
# smtp会话过程中的mail from地址
from_addr = "aryaky@126.com"
# smtp会话过程中的rcpt to地址
to_addr = "lilantao@gmail.com"
#to_addr = "aryaky@126.com"
# 信件内容
#   标题
subject = "test"
#   正文
text = "my test mail"

def mail(mailserver=None, username='', passwd='', from_addr='', to_addr='', subject='', text=''):
	"""
	Usage:
	mail('somemailserver.com', user@example.com, passwd, 'me@example.com', 'someone@example.com', 'test', 'This is a test')
	"""
	#   邮件头
	headers = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % (from_addr, to_addr, subject)
	#   邮件
	msg = headers + text
	
	try:
		svr = smtplib.SMTP(mailserver)
		# 设置为调试模式，就是在会话过程中会有输出信息
		svr.set_debuglevel(1)
		# ehlo命令，docmd方法包括了获取对方服务器返回信息
		svr.docmd("EHLO server")
		# auth login 命令
		svr.docmd("AUTH LOGIN")
		# 发送用户名，是base64编码过的，用send发送的，所以要用getreply获取返回信息
		svr.send(base64.encodestring(username))
		svr.getreply()
		# 发送密码
		svr.send(base64.encodestring(password))
		svr.getreply()
		# mail from, 发送邮件发送者
		svr.docmd("MAIL FROM: <%s>" % from_addr)
		# rcpt to, 邮件接收者
		svr.docmd("RCPT TO: <%s>" % to_addr)
		# data命令，开始发送数据
		svr.docmd("DATA")
		# 发送正文数据
		svr.send(msg)
		# 比如以\r\n.\r\n作为正文发送结束的标记
		svr.send("\r\n.\r\n")
		svr.getreply()
		# 发送结束，退出
		svr.quit()
	except:
		logging.exception("got exception when send mail")
		print "Got some exception when send mail"
	
	
def sendMail(asubject='', atext=''):
	return mail(mailserver, username, password, from_addr, to_addr, asubject, atext)
	
#VERSION = "0.200d"

DIR = '.'
#DIR = '/home/lilt/work/pystran/trunk'     # The working directory, save configure files there
#DIR = 'C:\\pystran\\svn\\'     # The working directory, save configure files there
#DIR = 'D:\\pytravian\\'     # The working directory, save configure files there
#DIR = 'D:\\WORK\\code\\pystran\\svn\\'     # The working directory, save configure files there
CONFIG = 'bot6.own.cfg'
BANNED = 'bot6.own.cfg'
#
#REPORT_URL = urlparse.urljoin(HOST, "berichte.php") # Report page URL
#MESSAGE_URL = urlparse.urljoin(HOST, "nachrichten.php") #Message page

# The resource sequence of TravianSession.resources[] and costs[]
WOOD = 0
CLAY = 1
IRON = 2
FOOD = 3
EAT = 4 # Eat only exist in costs[], 'eat' is the food consumption rate per hour

# The sequence in TravianSession.resource[WOOD]
STOCK = 0
CAP = 1
RATE = 2

# The sequence in TravianSession.builgings[]
BUILDING_TITLE = 0
BUILDING_LEVEL = 1
BUILDING_URL = 2

# The sequence of TravianSession.building_options[]
BUILDING_OPT_TITLE = 0
BUILDING_OPT_COSTS = 1
BUILDING_OPT_URL = 2

FIELDS_NAMES = [{'type':'wood', 'en':'Wood Cutter', 'cn':'伐木场'},
			   {'type':'clay', 'en':'Clay Pit', 'cn':'黏土矿'},
			   {'type':'iron', 'en':'Iron Mine', 'cn':'铁矿场'},
			   {'type':'food', 'en':'Crop Land', 'cn':'农场'}]
RES_NAMES = [{'type':'wood', 'en':'Wood', 'cn':'木'},
			   {'type':'clay', 'en':'Clay', 'cn':'泥'},
			   {'type':'iron', 'en':'Iron', 'cn':'铁'},
			   {'type':'food', 'en':'Food', 'cn':'粮'}]

# The number of each resource fields, sequence: WOOD, CLAY, IRON, FOOD for 
# each resource cell types. Currently Travian provides 6 type of resource cell, 12
# types of oasises. 
CELLS = [ \
	[3,3,3,9], # f1 
	[3,4,5,6], # f2
	[4,4,4,6], # f3
	[4,5,3,6], # f4
	[5,3,4,6], # f5
	[1,1,1,15]] # f6

LANG = 'cn' # Set to 'cn' or 'en'
# Resource Fields are:  Wood Cutter(伐木场), Clay Pit(黏土矿), Iron Mine(铁矿场) and Crop Land(农场)

HOST = 'http://s2.travian.cn'
		
class TravianSession(myproxy.PycurlWrapper):
	'''Maintain a particular account. 
		Main Responsibilities:
			Login
			Upgrading resource fields.
			Constructing buildings. 
			Producing army. 
			Report attack.
			Monitor system messages.
		Note: Sensitive to changes in site design.'''

	# Settings
	verbose = True  # Display verbose information
	host = HOST
	template_file = './report_template.html'
	villages = []
	village = ''
	villagename = ''
	# resources:
	#  The "resources is a list of 4 resources, each item consists of 3 values:
	#   current stock, storatge capacity and harvesting rate per hour. 
	#  The sequence of the fourresources are: wood, clay, iron, food.
	#
	resources = [ [0,0,0],  # WOOD: stock, capacity, rate/hour
				[0,0,0],    # CLAY: stock, capacity, rate/hour
				[0,0,0],    # IRON: stock, capacity, rate/hour
				[0,0,0]]    # FOOD: stock, capacity, rate/hour
		
	# Food production and consumption
	food_production = 0
	food_consumption = 0
	# Current upgrading(constructing) list
	constructings = []
	
	# fields:
	#  The "fields" is a list of resource fieldsF
	#  Format: [ type, level, url ]
	#    "type" could be CLAY, WOOD, IRON or FOOD
	#    "level" is the level of current field, it is an integer, not string
	#    "url" is the URL link of this field
	#  Example: [  ["clay", 2, 'build.php?id=2'], ["wood", 3, 'build.php?id=3'], ...  ]
	#
	fields = [] 

	# buildings
	#  The "buildings" is a list of in town buildings such as 中心大楼, 山洞, 集结点, 工地
	#  Format: [building_title, level, url]
	#
	buildings = []
	
	# building_options is list a buildings can be built on empty construction site
	#  Format: [ building_title,  costs, url ] 
	#   If resources insufficient, the url will be None
	#   The cost is a list of resources required. 
	#    costs = [WOOD, CLAY, IRON, FOOD, FoodConsumption/hour]
	building_options = [] 
	
	# reports
	#  A list of all repots title and detail link. 
	#   Format:  [ title, url ] 
	#    The url links to the detailed report of the message. 
	reports = []
	
	# cookie_file
	#   The absolute path of the cookie file
	cookie_file = ''
	
	postfile = None

	# The constructor
	def __init__(self, username, password, proxier=None, verbose=True):
		# verbose is the flag to identify whether display detailed infomation
		self.verbose = verbose
		# Account info
		self.username = username
		self.password = password
		# Initialize variables
		self.buildings = []
		self.building_options = []
		self.constructings = []
		self.attackings = []
		self.attackInfos = []
		self.armys = []
		self.reports = []
		self.fields = []
		self.omitVillages = []
		self. cookie_file = ''
		self.host = HOST
		self.x = 0
		self.y = 0
		self.ratio = [80,100,70,60,25] # CLAY:WOOD:IRON:FOOD:FOOD_LOW ratio
		if self.verbose:
			print "[MSG] Switch to account: %s" % self.username
		# Initialize proxy veriable
		if proxier: 
			self.proxier = proxier
			self.proxy = self.proxier.get()
			if self.verbose:
				print "[MSG] Turn on proxy: %s" % self.proxy
		else:
			self.proxy = ''
			#print "[MSG] Warning: Operating with no proxy in use."
		
	# Calculate the average level of each kind of resource fields
	def meanLevel(self):
		#The level summary of each kind of resource
		level_sum = [0,0,0,0]  # In the sequence of wood, clay, iron, food
		# The number of field of each kind of resource
		fields_num = [0,0,0,0] 
		# The average value of each resource fields
		level_avg = [0,0,0,0] 
		for field in self.fields:
			if field[0] == WOOD:
				level_sum[WOOD] += field[1]
				fields_num[WOOD] += 1
			elif field[0] == CLAY:
				level_sum[CLAY] += field[1]
				fields_num[CLAY] += 1
			elif field[0] == IRON:
				level_sum[IRON] += field[1]
				fields_num[IRON] += 1
			elif field[0] == FOOD:
				level_sum[FOOD] += field[1]
				fields_num[FOOD] += 1
		for i in range(len(level_sum)):
			level_avg[i] = float(level_sum[i]) / fields_num[i]
		return level_avg
	
	# Get bulding's level
	def getBuildingLevel(self, name):
		level = 0
		for building in self.buildings:
			if building[BUILDING_TITLE] == name:
				level += building[BUILDING_LEVEL]
		return level
	def saveData(self, filename, msg):
		try:
			filename = os.path.abspath(filename)
			if os.path.isfile(filename):
				os.remove(filename)
			fobj = open(filename, 'w')
			fobj.write(msg)
			fobj.close()
		except:
			print "[ERR] Saving file %s error" % filename  
	def readData(self, filename):
		try:
			filename = os.path.abspath(filename)
			if os.path.isfile(filename):
				fobj = open(filename, 'r')
				return fobj.read()
			else:
				return ''
		except:
			print "[ERR] Saving file %s error" % filename

	# Localized wrap of myproxy.PycurlWrapper::fetch()
	def safeFetch(self, url, postdata=None):
		id_str = 'travian'
		# Check the url is absolute
		url = str(url)
		if url.find('http://') == -1:
			url = urlparse.urljoin(self.host, url)
		url = url.replace('&amp;', '&')
		# Identify the page is from travian or a falut proxy
		count = 0
		while True:
			count += 1
			if count > 5: 
				self.contents = ''
				return False
			self.fetch(url, postdata)
			if self.contents.find('因为违规帐户被锁') >= 0:
				print '[ERR] Account been locked'
				self.logfile.write("%s\n" % self.username)
			occurs = re.findall(id_str, self.contents)
			if len(occurs) < 3: 
				# 'travian' appear less than 3 times indicates the page may not from travian.cn
				if self.proxier: # Switch proxy if proxier was set
					self.proxy = self.proxier.get()
					if self.verbose: print "[MSG] Faulty proxy. Switch proxy to:", self.proxy
				else:
					if self.verbose: print "[ERR] Unexpected page, may not from Travians.cn"
					self.contents = ''
					return False
			else: # Page from travian.cn confirmed
				return True
	# Map scan functions
	def z(self, x, y):
		return (400-y) * 801 + x + 401
	
	def xy(self, z):
		y = 400 - z/801
		x = z%801 + 401
		return [x, y]
	
	def randomScan(self, times=None):
		if times == None: times = 1
		for i in range(times):
			r_x = random.randint(0, 57)
			r_y = random.randint(-57, 0)
			x = 3 + r_x * 7
			y = -3 + r_y * 7
			if x > 400: x = 400
			if y < -400: y = 400
			z = self.z(x,y)
			#url = urlparse.urljoin(self.host, 'karte.php?z=')
			if self.verbose: print '[DBG] random scan: %d(%d,%d)' % (z, x, y)
			url = urlparse.urljoin( self.host, 'karte.php?z=' + str(z) )
			self.scanMap(url)
		
	

				
	def parseCell(self, url):
		'''The parseCell() gathers cell informations. Such as cell type, location,
		if it is occupied by a player, it also collect player's name, population,
		race and etc.
		   A cell is the basic unit of map, each of the cell has is own coordinate.
		A cell can be either an oasis or a resource cell. Cell could be in two 
		states, occupied (by player) or not titled (free to be occupied).'''
		try:
			self.safeFetch(url)
			#self.safeFetch(url)
			
			player_info = ['', '0', '', '']
			cell_info = None
			# Parse village name and location (x,y,z)
			m = re.search('<h1>.+?</h1>', self.contents)
			village_block = m.group()[4:-5]
			try:
				village, position = village_block.split()
			except:
				m = re.search('ddb">.+?</div>',village_block)
				village = m.group()[5:-6]
				m = re.search('&nbsp;.+?&nbsp;',village_block)
				position = m.group()[6:-6]
			x, y = position[1:-1].split('|')
			x = int(x); y = int(y)
			z = (400-y) * 801 + x + 401
			location_info = [str(x), str(y), str(z), village]
			
			# Identify the cell's type (resource cell or oasis cell)
			m = re.search('<img src="img/un/m/w\d+.jpg"', self.contents)
			if m: # The cell is an oasis
				oasis_info = [m.group()[20:-5]]
				resource_info = ['0','0','0','0']
			else: # The cell is an ordinary resource cell
				# Parse resource fields distribution
				m = re.search('<div id="f\d"></div>', self.contents)
				cell_id = int(m.group()[10:11])
				cell_id -= 1
				oasis_info = ['0']
				resource_info = []
				res = CELLS[cell_id]
				for field_num in res: # Convert int list to a string list
					resource_info.append(str(field_num))
			
			# Parse player info
			if self.contents.find('种族') >= 0: # Occupied cell, parse player info
				# Extract race
				m = re.search('<td>种族:</td><td>.+?</td>', self.contents)
				race_block = m.group()
				m = re.search('<b>.+?</b>', race_block)
				race = m.group()[3:-4]
				# Extract alliance
				m = re.search('<td>联盟:</td><td>.*?</td>', self.contents)
				alliance_block = m.group()[20:]
				m = re.search('>.*?</a>', alliance_block)
				alliance = m.group()[1:-4]
				# Extract player
				m = re.search('<td>所有者:</td><td>.+?</td>', self.contents)
				player_block = m.group()
				m = re.search('">.+?</a>', player_block)
				player = m.group()[2:-4]
				player = player.replace('<b>', '')
				player = player.replace('</b>', '')
				player = player.strip()
				print player # DEBUG
				# Extract population
				m = re.search('<td>居民:</td><td>.+</td>', self.contents)
				if m: # There is no population for occupied oasis
					population_block = m.group()
					m = re.search('\d+', population_block)
					population = m.group()
				else:
					population = '0'
				player_info = [player, population, race, alliance]
				pass
			else:
				player_info = ['', '0', '', '']

			# Organize the cell info
			cell_info = location_info + resource_info + oasis_info + player_info
			''' The cell_info format: 
			[ x, y, z, village_name, wood_cutters, clay_pits, iron_mines, crop_lands, 
			 oasis_type, player, population, race, aliance ]
			All data saved in cell_info are in type of string for the convenience of 
			post.'''
			# print "cell_info=", cell_info  # DEBUG
			return cell_info
		except:
			if self.verbose: print "[ERR] parse cell error. url = ", url
			print sys.exc_info()
			return False
			pass
	def deleteMessage(self, msgType):
		'''msgType: 
					 trade
		'''
		print "[MSG] Deleting", msgType, "messages" 

		if msgType == "trade":
			urlbase = "http://s6.travian.cn/berichte.php?t=2&"
		if msgType == "other":
			urlbase = "http://s6.travian.cn/berichte.php?t=4&"
		if msgType == "support":
			urlbase = "http://s6.travian.cn/berichte.php?t=1&"
		if msgType == "attack":
			urlbase = "http://s6.travian.cn/berichte.php?t=3&"
		url=urlbase
		self.safeFetch(url)
		
		#'<input type="Checkbox" name="n10" value="12345678">'
		'''
<td width="22"><input type="Checkbox" name="n9" value="34899040"></td>\n<td class="s7"><a href="berichte.php?id=34899040">赵客缦胡缨攻击铁血-1.小东团</a> </td>\n<td width="125" nowrap>08/09/16 12:20</td>\n</tr><tr>
		'''
		m = re.findall('<input type="Checkbox" name="n\d+" value="\d+">', self.contents)
		count1=0
		delpostion = 0
		while len(m) != 0:

			url2=''
			count2=0
			for x in m:
				#print x
				nx=re.search('n\d+', x)
				value=re.search('[0-9]{7,9}', x)
				first = self.contents.find(value.group())
				second = self.contents.find(value.group(), first+1)
				newpos = self.contents.find('(新)', second, second + 300)
				if newpos != -1 or msgType == 'trade':
					url2+='&'+nx.group()+'='+value.group()
					count2+=1
				
				#print url2
			count1+=count2
			if count2 != 0:
				url = urlbase+'del=%C9%BE%B3%FD' + url2
				self.safeFetch(url)
				#print "[DBG] Delete " + str(count2) + " messages this time"
				print "+", str(count2),  
				m = re.findall('<input type="Checkbox" name="n\d+" value="\d+">', self.contents)
				if delpostion != 0:
					url = urlbase + 's=' + str(delpostion*10)
					self.safeFetch(url)
					m = re.findall('<input type="Checkbox" name="n\d+" value="\d+">', self.contents)
				#delpostion = 0;
			else:
				delpostion += 1
				url = urlbase + 's=' + str(delpostion*10)
				self.safeFetch(url)
				m = re.findall('<input type="Checkbox" name="n\d+" value="\d+">', self.contents)

		print "\n[MSG] Delete " + str(count1) + " messages ALL"

				
	def parseCell2(self, url):
		'''The parseCell() gathers cell informations. Such as cell type, location,
		if it is occupied by a player, it also collect player's name, population,
		race and etc.
		   A cell is the basic unit of map, each of the cell has is own coordinate.
		A cell can be either an oasis or a resource cell. Cell could be in two 
		states, occupied (by player) or not titled (free to be occupied).'''
		if True:
			self.safeFetch(url)
			#self.safeFetch(url)
			
			player_info = ['', '0', '', '']
			cell_info = None
			# Parse village name and location (x,y,z)
			m = re.search('<h1>.+?</h1>', self.contents)
			village_block = m.group()[4:-5]
			try:
				village, position = village_block.split()
			except:
				m = re.search('ddb">.+?</div>',village_block)
				village = m.group()[5:-6]
				m = re.search('&nbsp;.+?&nbsp;',village_block)
				position = m.group()[6:-6]
			x, y = position[1:-1].split('|')
			x = int(x); y = int(y)
			print village, position
			z = (400-y) * 801 + x + 401
			location_info = [str(x), str(y), str(z), village]
			
			# Identify the cell's type (resource cell or oasis cell)
			m = re.search('<img src="img/un/m/w\d+.jpg"', self.contents)
			if m: # The cell is an oasis
				oasis_info = [m.group()[20:-5]]
				resource_info = ['0','0','0','0']
			else: # The cell is an ordinary resource cell
				# Parse resource fields distribution
				m = re.search('<div id="f\d"></div>', self.contents)
				cell_id = int(m.group()[10:11])
				cell_id -= 1
				oasis_info = ['0']
				resource_info = []
				res = CELLS[cell_id]
				for field_num in res: # Convert int list to a string list
					resource_info.append(str(field_num))
			
			# Parse player info
			if self.contents.find('种族') >= 0: # Occupied cell, parse player info
				# Extract race
				m = re.search('<td>种族:</td><td>.+?</td>', self.contents)
				race_block = m.group()
				m = re.search('<b>.+?</b>', race_block)
				race = m.group()[3:-4]
				# Extract alliance
				m = re.search('<td>联盟:</td><td>.*?</td>', self.contents)
				alliance_block = m.group()[20:]
				m = re.search('>.*?</a>', alliance_block)
				alliance = m.group()[1:-4]
				# Extract player
				m = re.search('<td>所有者:</td><td>.+?</td>', self.contents)
				player_block = m.group()
				m = re.search('">.+?</a>', player_block)
				player = m.group()[2:-4]
				player = player.replace('<b>', '')
				player = player.replace('</b>', '')
				player = player.strip()
				print player # DEBUG
				# Extract population
				m = re.search('<td>居民:</td><td>.+</td>', self.contents)
				if m: # There is no population for occupied oasis
					population_block = m.group()
					m = re.search('\d+', population_block)
					population = m.group()
				else:
					population = '0'
				player_info = [player, population, race, alliance]
				pass
			else:
				player_info = ['', '0', '', '']

			# Organize the cell info
			cell_info = location_info + resource_info + oasis_info + player_info
			''' The cell_info format: 
			[ x, y, z, village_name, wood_cutters, clay_pits, iron_mines, crop_lands, 
			 oasis_type, player, population, race, aliance ]
			All data saved in cell_info are in type of string for the convenience of 
			post.'''
			# print "cell_info=", cell_info  # DEBUG
			return cell_info


	# Scan map, get each cells' link and parse the detailed info of each cell
	def parseMapDetail(self, x=None, y=None, z=None):
		''' z is the absolute sequence number of a cell'''
		if x == y == z == None:
			raise "[ERR] parseMapDetail() parameter error"
		if z == None:
			z = self.z(x,y)
			print "[DBG] Scaning 7x7 cells arount: (%d|%d), z=%d please wait" % (x, y, z) 
		url = urlparse.urljoin(self.host,'karte.php')
		url = url + '?z=' + str(z)
		print "[DBG] parseMapDetail: url = ", url # DEBUG
		self.safeFetch(url)
		link_blocks = re.findall('"x"\:.+?"href":"karte\.php\?d=.+?"', self.contents)
		links = []
		for link_block in link_blocks:
			null = ""
			m= None
			exec('m={' + link_block + '}')
			link = m['href']
			url = urlparse.urljoin(self.host, link)
			cell_info = self.parseCell(url)
			if cell_info: 
				self.postCell(cell_info)
			#print "Sleep..", url
			#time.sleep( random.randint(2, 11-1) )
		
		
	# Parse 7x7 map, only gather the information on the map page
	#  If you would like to gather cell's detailed information such as 
	#  the number of each resource fileds, use parseMapDetail() instead
	def parseMap(self, x=None, y=None, z=None):
		''' z is the absolute sequence number of a cell'''
		if x == y == z == None:
			raise "[ERR] parseMap() parameter error"
		if z == None:
			z = self.z(x,y)
		url = urlparse.urljoin(self.host,'karte.php')
		url = url + '?z=' + str(z)
		print "[MSG] Scan 7x7 area arount (%d|%d)" % (x, y)
		self.safeFetch(url)
		#cell_blocks = re.findall('<area href="karte\.php\?d=.+?/>', self.contents)
		cell_blocks = re.findall('"x"\:.+?"href":"karte\.php\?d=.+?"', self.contents)
		mapcells = []
		self.savePage('./data/cell_page.html') # DEBUG
		#print len(cell_blocks)  # DEBUG
		for cell_block in cell_blocks:
			m = re.search('d=\d+', cell_block)
			z = m.group()[2:]
			null = ""
			cell=[]
			exec('m={' + cell_block + '}')
			if m['name']!='':
				# Occupied cell
				# Get cell information
				#[ village_name, username, population, alliance, x, y]
				exec( 'm[\'dname\'] = u\'"' + m['dname'] + '"\'.encode(\'utf8\')' )
				exec( 'm[\'name\'] = u\'"' + m['name'] + '"\'.encode(\'utf8\')' )
				exec( 'm[\'ally\'] = u\'"' + m['ally'] + '"\'.encode(\'utf8\')' )
				cell.append(m['dname'])
				cell.append(m['name'])
				cell.append(m['ew'])
				cell.append(m['ally'])
				cell.append(m['x'])
				cell.append(m['y'])
				if cell[0].find('占领的村庄') >= 0: cell[0] = '"占领的村庄"' # Error correction
				if cell[2] == '-': continue #cell[2] = '0'
				cell = [z] + cell
				mapcells.append(cell)
				#print cell
			else:
				# Empty cell
				pass
		# Save map cell data
		if len(mapcells) > 0:
			self.postMap(mapcells)
		else:
			if self.verbose: print "[MSG] No occupied map cell in this area"

	# Parse 7x7 map, only gather the green area information on the map page
	def parseMapGreen(self, x=None, y=None, z=None, type=None):
		''' z is the absolute sequence number of a cell'''
		if x == y == None:
			raise "[ERR] parseMap() parameter error"
		if z == None:
			z = self.z(x,y)
		if type == None:
				type = 0
		url = urlparse.urljoin(self.host,'karte.php')
		url = url + '?z=' + str(z)
		print "[MSG] Scan area arount (%d|%d)" % (x, y)
		self.safeFetch(url)
		cell_blocks = re.findall('/o\d+\.gif" />', self.contents)
		mapcells = []
		for cell_block in cell_blocks:
			m = re.findall('\d+\.', cell_block)
			if m[0] == '12.': #50%
				mapcells.append(50)
			elif m[0] in ['3.','6.','9.','10.','11.']: #25%
				mapcells.append(25)
		# Save map cell data
		mapcells.sort()
		countMaps = 0
		for c in  mapcells[-3:]:
				countMaps += c
		mapcells = [str(countMaps)] + [str(type)] + [str(x)] + [str(y)] + [url]
		self.postMapGreen(mapcells)

	# Parse 7x7 map, only gather the green area information on the map page
	def getMapAdder(self, x=None, y=None, z=None, type=None):
		''' z is the absolute sequence number of a cell'''
		if x == y == None:
			raise "[ERR] parseMap() parameter error"
		if z == None:
			z = self.z(x,y)
		if type == None:
				type = 0
		url = urlparse.urljoin(self.host,'karte.php')
		url = url + '?z=' + str(z)
		self.safeFetch(url)
		cell_blocks = re.findall('/o\d+\.gif" />', self.contents)
		mapcells = []
		for cell_block in cell_blocks:
			m = re.findall('\d+\.', cell_block)
			if m[0] == '12.': #50%
				mapcells.append(50)
			elif m[0] in ['3.','6.','9.','10.','11.']: #25%
				mapcells.append(25)
		# Save map cell data
		mapcells.sort()
		countMaps = 0
		for c in  mapcells[-3:]:
			countMaps += c
		return countMaps
	# Post data to tfen.us
	def post(self, data): 
		#return True
		if self.postfile :
				self.postfile.writelines( data+'\n')
				self.postfile.flush()
		print data
		return True
		
	# Post map info to tfen.us
	def postMap(self, cells):
		cell_strs = []
		for cell in cells:
			cell_str = ','.join(cell)
			cell_strs.append(cell_str)
		poststring = '\n'.join(cell_strs)
		self.post(poststring)
		#print "HTML:"
		#print self.contents # DEBUG
	# Post map info to tfen.us
	def postMapGreen(self, cells):
		cell_str = ','.join(cells)
		poststring = cell_str
		self.post(poststring)
	
	
	# Post cell info to tfen.us
	def postCell(self, cell):
		if cell[7] == '6' or cell[7] == '0' : return
		cell.append(str(self.getMapAdder( int(cell[0]),int(cell[1]) ) ))
		cell_str = ','.join(cell)
		pf = {'CELL':cell_str}
		if self.post(cell_str):
			#print '[MSG] Cell data updated'
			pass
		else:
			print '[MSG] Update cell info failed' # DEBUG
			self.savePage('./data/post_cell_failed.html')
			pass
		#print "HTML:"
		#print self.contents # DEBUG
	
	# Post account info to tfen.us
	def postRobot(self):
		return
		if self.x == self.y == 0:
			self.parseProfile()
		z = self.z(self.x, self.y)
		location_info = [str(z), str(self.x), str(self.y), self.username,\
						self.password, str(self.food_consumption)]
		resource_info = [str(self.resources[WOOD][RATE]), str(self.resources[CLAY][RATE]), \
			str(self.resources[IRON][RATE]), str(self.food_production - self.food_consumption)]
		# robot_info sequence:  [ z, x, y, username, password, population, 
		#   wood_rate, clay_rate, iron_rate, food_rate ]
		robot_info = location_info + resource_info
		#print robot_info # DEBUG
		robot_str = ','.join(robot_info)
		pf = {'ROBOT':robot_str}
		if self.post(pf):
			if self.verbose: print "[MSG] Robot data updated"
		else:
			print "[ERR] Robot data update failed"
		#print "HTML:"
		#print self.contents # DEBUG
	
	# Deal with system notice
	def jumpSysNotice(self):
		url = urlparse.urljoin(self.host , 'dorf1.php?ok')
		noticeStr = '点击<a href="' + url +'"><strong>开始</strong></a>继续游戏'
		if self.contents.find(noticeStr) >= 0:
			print "[MSG] System notice page found, jump..."
			self.safeFetch( url )
	
	# Deal with system notice
	def DatabaseError(self):
		if self.contents.find('Game Database is unavailable') >= 0:
			print "[MSG] Game Database is unavailable, jump..."
			return True
		else:
			return False
	# Login http://s6.travian.cn

	def login(self):
		# TODO: Get main page and identify if login is required.
		# Get login page
		login_url = 'login.php'
		login_post_url = 'dorf1.php'
		
		# Identify if login required
		self.safeFetch(login_post_url)
		if self.DatabaseError(): return False;
		self.jumpSysNotice()
		if not self.contents.find("生产力") >= 0 : # Login successful
			print "[DBG] Login required"
		#self.safeFetch(login_url)
		# Find the login input text box name
			try:
				m = re.search('<label>用户名:</label>.+maxlength="15">', self.contents, re.S)
				input_tag = m.group()
				m = re.search('name=".+?"', input_tag)
				input_username_id = m.group()[6:-1] # Username input text box name
				#print input_username_id 
				m = re.search('<label>密码:</label>.+maxlength="20">', self.contents, re.S)
				input_tag = m.group()
				m = re.search('name=".+?"', input_tag)
				input_password_id = m.group()[6:-1] # The password input text box name
				#print input_password_id 
				m = re.search('<input type="hidden" name=".{7}"', self.contents)
				input_hidden1_id = m.group()[-8:-1] # The hidden tag1 name
			except:
				if self.debug: self.savePage('./data/login_failed.html')
				print "[ERR] Login page may changed."
				print sys.exc_info()
				return False

			# Generate timestamp
			t = datetime.datetime.now()
			variety = random.randint(-72000, 36000) # Anti MultiHunter
			timestamp = str(int(time.mktime(t.timetuple())) + variety) # The seconds since 1970
			pf = {'w':'', 'login':timestamp, input_username_id:self.username, \
				input_password_id:self.password, input_hidden1_id:'', 'autologin':'ja'}
			#vtian.gm:  name="e2a30e3" value="aa9ea6dd51"
			#bugzilla:    name="e2a30e3" value="3242aa5c11"
		  
			# Login
			self.safeFetch(urlparse.urljoin(self.host, login_post_url), pf)
			# Verify login status
			if self.contents.find("启用cookie") >= 0: # Login failed
				print "[ERR] Login failed, account: %s" % username
				if self.debug: self.savePage('./data/login_failed.html')
				return False
		else:
			print "[DBG] Login skipped"

		if not self.contents.find("生产力") >= 0: # Login successful
			return False
		matchs = re.findall('<a href="\?newdid=\d+"', self.contents)
		self.villages = []
		for match in matchs:
			s = re.match('<a href="(\?newdid=\d+)"', match)
			self.villages.append(s.groups()[0])
		if len(self.villages) == 0 : self.villages = ['']
		#print '[DBG] Villages: ', self.villages #DEBUG
		return True
		
	# Parse profile
	def parseProfile(self):
		link=urlparse.urljoin(self.host, 'karte.php')
		self.safeFetch(link)
		m = re.findall('name="[x|y]p" value=".*" s', self.contents)
		
		sx = re.match('name="xp" value="(.*)" s', m[0])
		sy = re.match('name="yp" value="(.*)" s', m[1])

		self.x = int(sx.groups()[0])
		self.y = int(sy.groups()[0])
	
	# Parse news(reports or/and messages) based on the indicator
	def parseNews(self):
		''' The color of the reports/messages picture indicates if there has 
		any new messages/reports colored picture means new reports/messages 
		available, grey the opposite'''
		try:
			m = re.search('m\d\.gif', self.contents)
			# Left report, right message
			val = int(m.group()[1:-4])
		except:
			print "[ERR] parse news error"
			return
	
		if val == 1: # New report(s) and new message(s)
			print "[MSG new reports and messages available"
			self.parseReports()
			self.parseMessages()
		if val == 2: # New message(s) only
			print "[MSG] new messages available"
			self.parseMessages()
		if val == 3: # New report(s) only
			print "[MSG] new reports available"
			self.parseReports()

	# Parse reports (Attacking, Trading, Assistanting and etc.)
	def parseReports(self):
		'''This function/method is expected to be called by parseNews(), as it 
		can smartly identify if there is any new reports available, so as to 
		avoid unnessary traffic'''
		host = self.host
		reports = [] # DEBUG ONLY
		page_url = 'berichte.php'
		page_url = urlparse.urljoin(self.host, page_url)
		self.safeFetch(page_url)
		while 1:#try:
			m = re.search('<form.+?</form', self.contents, re.S)
			form_block = m.group()
			# Extract each report's link
			urls = []
			links_blocks = re.findall('<a href="berichte.php.+?>', form_block)
			for links_block in links_blocks:
				m = re.search('".+?"', links_block)
				link = m.group()[1:-1]
				urls.append(urlparse.urljoin(self.host, link)) # FIXME
			checkbox_blocks = re.findall('<input type="Checkbox".+?>', form_block)
			# Extract check box name and value, prepare for delete reports
			dict_list = []
			for checkbox_block in checkbox_blocks:
				m = re.search('name=".+?"', checkbox_block)
				name = m.group()[6:-1]
				m = re.search('value=".+?"', checkbox_block)
				value = m.group()[7:-1]
				dict_list.append((name,value))
				print name, value
			# Parse each report detail
			for i in range(len(urls)):
				parseReportDetail(urls[i])
			pf = dict(dict_list)
			# Delete reports
			print pf
			break
		#except:
		#       print "[ERR] Parse reports error"
		
	def parseMessages(self):
		'''This function/method is expected to be called by parseNews(), as it 
		can smartly identify if there is any new message available, so as to 
		avoid unnessary traffic'''
		print "[MSG] parse messages not implemented yet"
		
	# Parse 村落概貌 and get resource status
	def parseDorf1(self):
		page_url = "dorf1.php" + self.village
		page_url = urlparse.urljoin(self.host, page_url)
		if self.current_url <> page_url:
			self.safeFetch(page_url)
		
		# Check if page changed
		if self.contents.find("生产力") < 0:  
			print "[ERR] dorf1 page may changed"
			return
		
		# Get resource harvesting rates
		try:
			rates = re.findall('<b>\d+&nbsp;</b>', self.contents)
			for i in range(len(rates)):
				self.resources[i][RATE] = int(rates[i][3:-10])
		except:
			print "[ERR] Parase drof1 error. Can't get resource rates."
			return False
		
		# Get current resource stocks & capacities
		try:
			pattern = re.compile('\d+/\d+')
			pairs = pattern.findall(self.contents)
			resources = []
			for i in range(len(pairs)):
				val1, val2 = pairs[i].split('/')
				if i == 4:
					self.food_consumption = int(val1)
					self.food_production = int(val2)
				else:
					self.resources[i][0] = int(val1)
					self.resources[i][1] = int(val2)
			
			# Get resource fields' status: resource field type, level and URL
			pattern_map = re.compile('<map name="rx".+</map')
			m = pattern_map.search(self.contents)
			maps = m.group()
			
			pattern_url = re.compile('build\.php\?id=\d+')
			pattern_level = re.compile('title=".+"')
			fieldlist = []
			p1=p2=0
			while True:
				p1 = maps.find("<area", p2)
				if p1 == -1 : break
				p2 = maps.find(">", p1)
				fieldlist.append(maps[p1:p2])
			self.fields = []
			for field in fieldlist:
				if field.find('村庄中心') >= 0: continue # Skip Town Centre
				m = pattern_url.search(field)
				url = m.group()
				m = pattern_level.search(field)
				levlel_tmp = m.group()
				if field.find('伐木场') >= 0: type = WOOD
				elif levlel_tmp.find('黏土矿') >= 0: type = CLAY
				elif levlel_tmp.find('铁矿场') >= 0: type = IRON
				elif levlel_tmp.find('农场') >= 0: type = FOOD
				level = int(field[-3:-1])
				self.fields.append([type, level, url])
		except:
			print "[ERR] parsaeDorf1 error. Can't get resource stocks/capacities."
			return False
		p1 = p2 = 0
		p1 = self.contents.find('<h1>')
		p2 = self.contents.find('</h1>', p1)
		self.villagename = self.contents[p1+4:p2]

		# Update constructing status
		self.parseConstructing()
		
		# Get army status
		self.parseArmy()
		# Update attack status
		self.parseAttacking()


	# Parase 村庄中心 and get building status
	def parseDorf2(self):
		page_url = 'dorf2.php'
		page_url = urlparse.urljoin(self.host, page_url)
		if page_url <> self.current_url:
			self.safeFetch(page_url)
		if self.debug: self.savePage('./data/dorf2.html') # DEBUG
		building_links = []
		try:
			# Get town map block
			m = re.search('<map name="map1">.+?</map', self.contents, re.S)
			map_block = m.group()
			# Get all buildings, include construction_site(工地)
			buildings = re.findall('<area href="build.php.+?>', map_block)
			# Parse each building
			for building in buildings:
				# Get building link
				m = re.search('href="build.php.+?"', building)
				link = m.group()[6:-1]
				# Get bulding title
				m = re.search('title=".+?"', building)
				title = m.group()[7:-1]
				# Get level
				parts = title.split()
				if len(parts) == 1:
					level = 0
				else:
					title = parts[0]
					level = int(parts[2])
				# Add bulidings info into list, eliminate duplicates
				if not link in building_links: 
					building_links.append(link)
					link = urlparse.urljoin(self.host, link) # Convert to absolute link
					self.buildings.append([title, level, link])
		except:
			logging.error("[ERR] Dorf2 parsing failed.")
			return False
	
	# Parse 集结点 attack
	#准备第一步直接吸本页内容，不做计算和引申
	#&gid=16&id=39
	def parseAttackPage(self):
		"""解析集结点页面
		"""
		#如果没有攻击就不解析这个村子
		if not (len(self.attackings) > 0) :
			return False

		page_url = 'build.php' + self.village + '&gid=16&id=39'
		page_url = urlparse.urljoin(self.host, page_url)
		if page_url <> self.current_url:
			self.safeFetch(page_url)
		#如果攻击多需要多交互一次，迷惑MH的考虑
		if self.contents.find('显示全部') != -1:
			page_url += '&k'
			self.safeFetch(page_url)
			
		#if self.debug: self.savePage('./data/build39.html') # DEBUG
			
		self.attackInfos = []
		
		p1 = p2 = 0
		p1 = self.contents.find('返回的部队')
		if p1 == -1:
			return False
		p2 = self.contents.find('村庄里的军队')
		if p2 == -1:
			return False

		all = self.contents[p1:p2]
		pattern_items = re.compile('(\d+)')
		pattern_time = re.compile('\d+:\d+:\d+')
		m = pattern_items.search(all[0:20])
		if m:
			item = m.group()
			itemn = int(item)
		else:
			return False
		pr1 = pr2 = 0
		#每个<p></p>标签内的内容为一波部队
		for i in range(itemn):
			#获取一波部队的信息
			pr1 = all.find('<p>', pr2)
			if pr1 == -1: break
			pr2 = all.find('</p>', pr1)
			row = all[pr1:pr2]
			
			#第一个tr的内容是发兵村和目标村
			p1 = p2 = 0
			p1 = row.find('<tr', p2)
			p2 = row.find('</tr>', p1)
			row1 = row[p1:p2]
			
			'''
			<tr class="cbg1"><td width="21%"><a href="karte.php?d=335118&c=f3"><span class="c0">2专心务农</span></a></td>
			<td colspan="10" class="b"><a href="karte.php?d=440801&c=d6"><span class="c0">对吴钩霜雪明的支援</span></a></td></tr>
			'''
			#取对方的url
			p1 = p2 = 0
			p1 = row1.find('<a href=', 0)
			p1 = row1.find('"', p1) + 1
			p2 = row1.find('"', p1)
			villageUrl = row1[p1:p2]
			
			#取对方的村名
			p1 = p2
			p2 = row1.find('</span>', p1)
			p1 = row1.find('<span')
			p1 = row1.find('>', p1) + 1
			villageName = row1[p1:p2]
			
			#获取攻击类型
			p1 = row1.find('<span', p2)
			p1 = row1.find('>', p1) + 1
			p2 = row1.find('</span>', p1)
			attackType = row1[p1:p2]
			
			#获取攻击时间
			p1 = row.find('目的地')
			p1 = row.find('')
			
			m = pattern_time.findall(row)
			if len(m) != 2:
				print "[ERR] 攻击时间解析失败。格式改变？"
				return False
			leftTime = m[0]
			endTime = m[1]
			self.attackInfos.append([villageUrl, villageName, attackType, leftTime, endTime])
			
			

	def parseEnemyVillage(self):
		"""解析集结点页面
		"""
		#如果没有攻击详细信息就不再解析
		if not (len(self.attackInfos) > 0) :
			return False

		for i in range(len(self.attackInfos)):
			page_url = self.attackInfos[i][0]
			page_url = urlparse.urljoin(self.host, page_url)
			if page_url <> self.current_url:
				self.safeFetch(page_url)
			#找到小框
			'''
			<div class="map_details_right">
			<div class="f10 b"><div class="ddb">&nbsp;CCY#1</div><div class="ddb">&nbsp;(-184|-153)&nbsp;</div></div>			
			<table class="f10" style="clear:both;">			<tr>
			<td><img src="img/un/a/x.gif" width="3" height="12" border="0"></td>
			<td>种族:</td><td> <b>高卢人</b></td>
			</tr>		<tr>
			<td><img src="img/un/a/x.gif" width="3" height="12" border="0"></td>
			<td>联盟:</td><td><a href="allianz.php?aid=1591">凤凰¤ۣۜ.涅磐</a></td>
			</tr>		<tr>
			<td><img src="img/un/a/x.gif" width="3" height="12" border="0"></td>
			<td>所有者:</td><td><a href="spieler.php?uid=84827"> <b>ccyycc</b></a></td></tr><tr>
			<td><img src="img/un/a/x.gif" width="3" height="12" border="0"></td>td>居民:</td><td><b> 787</b></td>
			</tr></table>		</div>
			'''
			position1 = position2 = position3 = 0
			position1 = self.contents.find('map_details_right')
			#找坐标
			position2 = self.contents.find(self.attackInfos[i][1], position1)
			position2 = self.contents.find('<div', position2)
			position2 = self.contents.find('(', position2)
			position3 = self.contents.find(')', position2)+1
			strIP = self.contents[position2:position3]
			self.attackInfos[i].append(strIP)
			
			#找种族
			position2 = self.contents.find('种族:', position1)
			position2 = self.contents.find('<b>', position2) + 3
			position3 = self.contents.find('</b>', position2) #- 1
			strHuman = self.contents[position2:position3]
			self.attackInfos[i].append(strHuman)
			#找联盟
			position2 = self.contents.find('联盟:', position1)
			position2 = self.contents.find('"', position2) + 1
			position3 = self.contents.find('"', position2) #- 1
			strAllyUrl = self.contents[position2:position3]
			self.attackInfos[i].append(strAllyUrl)
			position2 = self.contents.find('>', position3) + 1
			position3 = self.contents.find('<', position2) #- 1
			strAllyName = self.contents[position2:position3]
			self.attackInfos[i].append(strAllyName)
			#找帐号
			position2 = self.contents.find('所有者:', position1)
			position2 = self.contents.find('"', position2) + 1
			position3 = self.contents.find('"', position2) #- 1
			strUserUrl = self.contents[position2:position3]
			self.attackInfos[i].append(strUserUrl)
			position2 = self.contents.find('<b>', position3) + 3
			position3 = self.contents.find('</b>', position2) #- 1
			strUserName = self.contents[position2:position3]
			self.attackInfos[i].append(strUserName)			
			#人口
			position2 = self.contents.find('居民:', position1)
			position2 = self.contents.find('<b>', position2) + 3
			position3 = self.contents.find('</b>', position2) #- 1
			strPeoples = self.contents[position2:position3]
			self.attackInfos[i].append(strPeoples)
			
				


	# Parse current constructing status
		# Parse current constructing status
	def parseConstructing(self):
		self.constructings = []
		p1 = p2 = 0
		p1 = self.contents.find('建造中:')
		if p1 == -1:
			return False    # Currently no constructing
		p1 = self.contents.find('<table', p1)
		p2 = self.contents.find('</table', p1)
		table = self.contents[p1:p2]
		# Each row(<tr> tag) is a constructing building
		pattern_time = re.compile('\d+:\d+:\d+')
			
		p1 = p2 = 0
		while True:
			p1 = table.find('<tr>', p2)
			if p1 == -1: break
			p2 = table.find('</tr>', p1)
			row = table[p1:p2]
			m = pattern_time.search(row)
			if m:
				time_to_finish = m.group()
			
			p3 = p4 = 0
			p3 = row.find('<td',p3)
			p3 = row.find('<td',p3+1)
			p4 = row.find('</td', p3)
			tmp = row[p3:p4]
			p3 = tmp.find(' ')
			building = tmp[4:p3]  # The name of building
			pattern_level = re.compile('\d+')
			m = pattern_level.search(tmp)
			level = m.group()       # The level number upgrading
			#print building, level, time_to_finish # DEBUG
			self.constructings.append([building, level, time_to_finish])
	
	def parseArmy(self):
		self.armys = []
		p1 = p2 = 0
		p1 = self.contents.find('军队:')
		if p1 == -1: raise "Can't find Army segment!"    # Error
		p1 = self.contents.find('<table', p1)
		p2 = self.contents.find('</table', p1)
		table = self.contents[p1:p2]
		p1 = table.find('无')
		if p1 >0 : return False    # Currently no army
		# Each row(<tr> tag) is a army
		p1 = p2 = 0
		while True:
			p1 = table.find('<tr>', p2)
			if p1 == -1: break
			p2 = table.find('</tr>', p1)
			row = table[p1:p2]
			#个数
			pattern_number = re.compile('\d+')
			p3 = p4 = 0
			p3 = row.find('<b>',p4)
			p4 = row.find('</b>', p3)
			m = pattern_number.search(row[p3:p4])
			if m:
				army_number = m.group()
			else:
				print '[DBG]Error parse dorf1 army table ... '
				continue
			#种类
			p3 = row.find('<td>',p4)
			p4 = row.find('</td', p3)
			army_type = row[p3+4:p4]

			self.armys.append([army_type, army_number])

	def parseAttacking(self):
		self.attackings = []
		p1 = p2 = 0
		p1 = self.contents.find('部队移动:')
		if p1 == -1:
			return False    # Currently no attacking
		p1 = self.contents.find('<table', p1)
		p2 = self.contents.find('</table', p1)
		table = self.contents[p1:p2]
		p1 = table.find('att1.gif')
		if p1 == -1:
			return False    # Currently no attacking
		# Each row(<tr> tag) is a constructing building
		pattern_time = re.compile('\d+:\d+:\d+')
		p1 = p2 = 0
		while True:
			p1 = table.find('<tr>', p2)
			if p1 == -1: break
			p2 = table.find('</tr>', p1)
			row = table[p1:p2]
			
			pattern_attack = re.compile('att\d')
			pattern_definde = re.compile('def\d')
			p3 = p4 = 0
			p3 = row.find('<td',p4)
			p4 = row.find('</td', p3)
			m = pattern_attack.search(row[p3:p4])
			if m:
				attack_type = m.group()
			else:
				#print '[DBG]Error parse dorf1 attack table ... '
				continue
			p3 = row.find('<td',p4)
			p4 = row.find('</td', p3)
			tmp = row[p3:p4]
			pattern_level = re.compile('\d+')
			m = pattern_level.findall(tmp)
			level = m[-1]       # The level number upgrading

			tmp = row[p4:]
			m = pattern_time.search(tmp)
			if m:
				time_to_finish = m.group()
			else:
				print '[DBG]Error parse dorf1 attack table ... '
				continue

			#print attack_type, level, time_to_finish # DEBUG
			self.attackings.append([attack_type, level, time_to_finish])

	# Parse '工地', get a list of available building options
	def parseConstructionSite(self):
		# Found a empty construction site first
		isFound = False
		for building in self.buildings:
			if building[BUILDING_TITLE] == '工地':
				url = building[BUILDING_URL]
				isFound = True
				break
		if not isFound: 
			if self.verbose: print "[MSG] No more space to build new construtions."
			return 
		
		# Get the page
		self.safeFetch(url)
		try:
			build_blocks = self.contents.split('<h2>')
			#print build_blocks
			for i in range(len(build_blocks)):
				if i == 0: continue
				p1 = build_blocks[i].find('<')
				# Get building title
				title = build_blocks[i][:p1]
				p1 = title.find('.') # Get rid of the number in front of building name
				if p1 >= 0: title = title[p1+1:].strip()
				# Get build link 
				m = re.search('<a href="dorf2.php.+?>', build_blocks[i])
				if m:
					link = m.group()[9:-2]
					link = link.replace('&amp;', '&')
					link = urlparse.urljoin(self.host, link)
				else: # In case of 资源不足 or已经有建筑在建造中
					link = None 
				#print title, link # DEBUG
				# Get the costs
				resources = re.findall('>\d+', build_blocks[i])
				required_resources = [0,0,0,0,0]
				for i in range(5):
					required_resources[i] = int(resources[i][1:])
				#print required_resources # DEBUG
				# Add
				self.building_options.append([title, required_resources, link])
		except:
			print "[ERR] Parsing construction site error"
			
	# Display resource status and resource field levels
	def display(self):
		""" Diaplay the current resource stock and level of resource fields"""
		self.buildings.sort()
		self.fields.sort()
		if self.villagename not in self.omitVillages:
			self.omitVillages.append(self.villagename)
		#outMsg = "========" + self.username + self.villagename + "(" + unicode(self.x) + ',' + unicode(self.y) + ')' + unicode(self.food_comsumption) +'======'
		outMsg = "========" + self.username + ' ' + self.villagename + " (" + str(self.x) + ', ' + str(self.y) + ') 耗粮:' + str(self.food_consumption) +'======'
		logging.info(outMsg)
		outMsg = RES_NAMES[WOOD][LANG] + ':' + str(self.resources[WOOD][STOCK]) + '/' + str(self.resources[WOOD][CAP]) + ' ' + str(self.resources[WOOD][RATE]) + '/h ' + \
			RES_NAMES[CLAY][LANG]+ ':'+ str(self.resources[CLAY][STOCK])+ '/'+ str(self.resources[CLAY][CAP]) + ' ' + str(self.resources[CLAY][RATE]) + '/h ' + \
			RES_NAMES[IRON][LANG]+ ':'+ str(self.resources[IRON][STOCK])+ '/'+ str(self.resources[IRON][CAP]) + ' ' + str(self.resources[CLAY][RATE]) + '/h ' + \
			RES_NAMES[FOOD][LANG]+ ':'+ str(self.resources[FOOD][STOCK])+ '/'+ str(self.resources[FOOD][CAP]) + ' ' + str(self.resources[FOOD][RATE]) + '/h' 
		logging.info(outMsg)
		'''
		print "Resources: ",
		print " %s:%d/%d %d/h" % (RES_NAMES[WOOD][LANG], self.resources[WOOD][STOCK], self.resources[WOOD][CAP], self.resources[WOOD][RATE]), \
			"  %s:%d/%d %d/h" % (RES_NAMES[CLAY][LANG], self.resources[CLAY][STOCK], self.resources[CLAY][CAP], self.resources[CLAY][RATE]), \
			"  %s:%d/%d %d/h" % (RES_NAMES[IRON][LANG], self.resources[IRON][STOCK], self.resources[IRON][CAP], self.resources[IRON][RATE]), \
			"  %s:%d/%d %d/h" % (RES_NAMES[FOOD][LANG], self.resources[FOOD][STOCK], self.resources[FOOD][CAP], self.food_production - self.food_consumption)
		'''
		'''
		print "------------------------------------------------------------------------"
		print "Resource_Fields"
		for i in range(len(self.fields)/6):
			print "  %s: %d | %s: %d | %s: %d | %s: %d | %s: %d | %s: %d" % (  \
				FIELDS_NAMES[self.fields[i*6+0][0]][LANG].rjust(6), self.fields[i*6+0][1], \
				FIELDS_NAMES[self.fields[i*6+1][0]][LANG].rjust(6), self.fields[i*6+1][1], \
				FIELDS_NAMES[self.fields[i*6+2][0]][LANG].rjust(6), self.fields[i*6+2][1], \
				FIELDS_NAMES[self.fields[i*6+3][0]][LANG].rjust(6), self.fields[i*6+3][1], \
				FIELDS_NAMES[self.fields[i*6+4][0]][LANG].rjust(6), self.fields[i*6+4][1], \
				FIELDS_NAMES[self.fields[i*6+5][0]][LANG].rjust(6), self.fields[i*6+5][1] )
		print "------------------------------------------------------------------------"
		'''
		
		'''
		# Output buildings
		print "Buildings(%d):" % len(self.buildings) 
		count = 1
		for building in self.buildings:
			if building[BUILDING_TITLE] == '工地': continue
			print "%s:  %d " % (building[BUILDING_TITLE].rjust(8), building[BUILDING_LEVEL]),
			if (count)%5 == 0: print
			else: print "|",
			count += 1
		if not (count-1)%5 ==0: print
		print "------------------------------------------------------------------------"
		# Output under construction buildings
		if len(self.armys) > 0 :
			print "军队(%d):" % len(self.armys) ,
			for army in self.armys:
				print "(%s,%s)" % (army[1], army[0]) ,
			print

		# Output under construction buildings
		if len(self.constructings) > 0 :
			print "Constructing(%d):" % len(self.constructings) ,
			for constructing in self.constructings:
				print "( %s, %s, %s )" % (constructing[0], constructing[1], constructing[2]) ,
			print
		'''
		# Output under attackings
		if len(self.attackings) == 0 :
			# 持久化攻击波数来判断是否有攻击变化
			# 清空持久化记录
			x = re.search('\d+',self.village)
			attFileName = './data/'+x.group()+'.att'
			#波数
			self.saveData(attFileName, '')
		else:
			atts = ''
			#print "=================== %s %s(%d,%d) P:%d =================" % \
			#	(self.username, self.villagename,  self.x, self.y, self.food_consumption), self.host[7:9]
			print "Attackings(%d):" % len(self.attackings) ,
			for attacking in self.attackings:
				if attacking[0] == 'att1': sys.stdout.write("\x1b[01;05;37;41m")
				print "type: %s  level:%s  %s" % (attacking[0], attacking[1], attacking[2])
				atts += "%s:%s " % (attacking[0], attacking[1])
				if attacking[0] == 'att1': 
					m = re.findall('(\d+):(\d+):\d+', attacking[2])
					if '0' == m[0][0] and '0' == m[0][1][0] and  '6' >= m[0][1][1] : print '\a',
					sys.stdout.write("\x1b[00m")
					#print
			
			#sendMail
			# 持久化攻击波数来判断是否有攻击变化
			# todo 需要持久化每个攻击的发兵村，到达时间
			x = re.search('\d+',self.village)
			attFileName = './data/'+x.group()+'.att'
			#波数
			recordatts = self.readData(attFileName)
			if atts != recordatts:
				subject = self.villagename + '受到攻击'
				text = "===== %s %s(%d,%d) 人口:%d =====\n" % \
					(self.username, self.villagename,  self.x, self.y, self.food_consumption)#, self.host[7:9]
				text += ("Attackings(%d):\n" % len(self.attackings) )
				for attacking in self.attackings:
					text += ("type: %s  波数:%s 剩余时间 %s\n" % (attacking[0], attacking[1], attacking[2]))
				text += "=============\n"
				bOwn = False
				detailAll = ''
				detailEmit = ''
				#
				for attackInfo in self.attackInfos:
					#[villageUrl, villageName, attackType, leftTime, endTime]
					detailItem = ("%s %s村庄人口:%s;种族:%s;帐号:%s;联盟:%s; %s, 剩余时间 %s, 到达时间 %s\n" % \
								  (attackInfo[1], attackInfo[5], attackInfo[11], attackInfo[6], attackInfo[10], attackInfo[8], attackInfo[2], attackInfo[3], attackInfo[4]))
					detailAll += detailItem
					if attackInfo[1] not in ('6001', '6006', '汾阳', '忻州'):
						detailEmit += detailItem

				textEnd = ''
				textEnd += "=====说明=====\n"
				textEnd += "\tatt1: 主村攻击; att3: 绿州攻击\n"
				textEnd += "暂时更新到这里，有建议可以直接回复"
				textEnd += "攻击详细信息问题已经修改"
				textEnd += "账户登录失败下一轮才会重试"
				textEnd += "更新坐标信息"
				textEnd += "TODO:将此部分内容移植到配置文件"
				textEnd += "TODO:每个账户配置独立的告警地址"
				#发送
				mails = []
				for line in open('email.txt'):
					line = line.strip()
					if len(line) == 0: continue # Skip empty line
					if line[0] == '#': continue # Skip comment line
					mails.append(line)
				print "[MSG] email list", mails
				#msg = text + detailEmit + textEnd
				#mail(mailserver, username, password, from_addr, 'lilantao@gmail.com', subject, msg)
				#print "[DBG] send mail to llt"
				if len(detailEmit) != 0:
					msg = text + detailEmit + textEnd
					print subject
					for emailAddr in mails:
						print "[MSG] send mail to", emailAddr
						mail(mailserver, username, password, from_addr, emailAddr, subject, msg)
				
					print "[MSG] send mail"
				else:
					print "[MSG] attack was omited"			
				self.saveData(attFileName, atts)
			
		'''
		if len(self.attackings) + len(self.constructings) + len(self.armys) > 0 :
			print "------------------------------------------------------------------------"
		if len(self.reports) > 0 :
			print "Reports:"
			for report in self.reports:
				print "  %s  %s" % (report[2], report[0])
			print "------------------------------------------------------------------------"
		'''
	# Generate a html report
	def genReport(self):
		filename = os.path.normpath(os.path.join(os.path.abspath(DIR), self.template_file))
		fobj = open(filename)
		template = fobj.read()
		template = template.replace('{VILLAGE}', str(self.username))
		template = template.replace('{WOOD_RATE}', str(self.wood_rate))
		template = template.replace('{CLAY_RATE}', str(self.clay_rate))
		template = template.replace('{IRON_RATE}', str(self.iron_rate))
		template = template.replace('{FOOD_RATE}', str(self.food_rate))
		template = template.replace('{WOOD_CAP}', str(self.wood_capacity))
		template = template.replace('{CLAY_CAP}', str(self.clay_capacity))
		template = template.replace('{IRON_CAP}', str(self.iron_capacity))
		template = template.replace('{FOOD_CAP}', str(self.food_capacity))
		template = template.replace('{WOOD}', str(self.wood))
		template = template.replace('{CLAY}', str(self.clay))
		template = template.replace('{IRON}', str(self.iron))
		template = template.replace('{FOOD}', str(self.food))
		template = template.replace('{FOOD_CONS}', str(self.food_consumption))
		template = template.replace('{FOOD_PROD}', str(self.food_production))
		# Generate resource fields report
		resource_field = ''
		field_name = '{RES_FIELD_NAME_'
		field_level = '{RES_FIELD_LEVEL_'
		for i in range(len(self.fields)):
			target = field_name + str(i+1) + '}'
			template = template.replace(target, FIELDS_NAMES[self.fields[i][0]][LANG])
			target = field_level + str(i+1) + '}'
			template = template.replace(target, str(self.fields[i][1]))
		return template
	
	def enableGoldCoins(self):
		if self.verbose: print "[MSG] Try to enable gold coins"
		url = urlparse.urljoin(self.host, 'plus.php?id=3')
		self.safeFetch(url)
		link_blocks = re.findall('<a href="plus\.php\?id=3.+?>激活</a>', self.contents)
		#print link_blocks
		enable_urls = []
		for link_block in link_blocks:
			m = re.search('a=\d+', link_block)
			a = int(m.group()[2:])
			if a < 1 or a > 4: continue # Use resource production increase function only
			m = re.search('href=".+?"', link_block)
			link = m.group()[6:-1]
			url=urlparse.urljoin(self.host, link)
			enable_urls.append(url)
		print enable_urls # DEBUG
		tmp = self.retry
		tmp_proxy = self.proxy
		self.proxy = '' # disable proxy
		self.retry = 1  # disable retry
		for enable_url in enable_urls:
			if self.verbose: print "[MSG] Enable gold coins", enable_url
			self.fetch(enable_url) # Don't retry or use safeFetch()
			pass
		self.retry = tmp                # restore retry
		self.proxy = tmp_proxy  # restore proxy
		
	# Upgrade a Factory
	# Factories are: Saw Mill(鋸木廠), Brickyard(黏土廠), Iron Foundry(鑄鉄廠), Grain Mill(磨坊), 
	def upgradeFactory(self):
		print "Not implemented yet"
	
	def testStrategy(self):
		try:
			to_upgrade = self.strategyLowestFirst()
			print "[DBG] LowestFirst strategy suggests upgrading:", FIELDS_NAMES[to_upgrade][LANG]
			to_upgrade = self.strategyRatioBased()
			print "[DBG] RatioBased strategy suggests upgrading:", FIELDS_NAMES[to_upgrade][LANG]
			to_upgrade = self.strategLevelBalanced()
			print "[DBG] LevelBalanced strategy suggests upgrading:", FIELDS_NAMES[to_upgrade][LANG]
		except:
			pass
		
	# Make sure the clay rate top the list. 
	def strategyRatioBased(self):
		# In case of one particular resource extremely low
		stock = [0,0,0,0]
		for i in range(len(stock)):
			stock[i] = self.resources[i][STOCK]
		lowest = min(stock)
		highest = max(stock)
		if lowest >= 20 and float(highest)/lowest > 5:
			return stock.index(lowest)
		if lowest < 20:
			return stock.index(lowest) 
		
		# Ratio base strategy
		if float(self.resources[CLAY][RATE])/self.resources[FOOD][RATE] > float(self.ratio[CLAY])/self.ratio[4]:
			return FOOD
		if float(self.resources[CLAY][RATE])/self.resources[WOOD][RATE] < float(self.ratio[CLAY])/self.ratio[WOOD]:
			return CLAY
		if float(self.resources[WOOD][RATE])/self.resources[IRON][RATE] < float(self.ratio[WOOD])/self.ratio[IRON]:
			return WOOD
		if float(self.resources[IRON][RATE])/self.resources[FOOD][RATE] < float(self.ratio[IRON])/self.ratio[FOOD]:
			return IRON
		return FOOD
	
	# Calculate which kind of resource field to upgrade, based on which is the lowest rate*time+stock
	def strategyLowestFirst(self):
		points = [0,0,0,0]
		for i in range(len(points)):
			points[i] = self.resources[i][RATE] * 8 + self.resources[i][STOCK]
		lowest = min(points)
		to_upgrade = points.index(lowest)
		return to_upgrade

	# Calculate which kind of resource field to upgrading, based on level average
	def strategLevelBalanced(self):
		level_avg = self.meanLevel()
		# Calculate which resource to upgrade
		index = 0
		min = -1
		for i in range(len(level_avg)):
			if min == -1: 
				min = level_avg[i]
				index = i
			if level_avg[i] < min:
				min = level_avg[i]
				index = i
		
		to_upgrade = index # The type of resource fields to upgrade
		return to_upgrade
	
	# Upgrade a Resource Field
	# Resource Fields are:  Wood Cutter(伐木场), Clay Pit(黏土矿), Iron Mine(铁矿场) and Crop Land(农场)
	def upgradeField(self, to_upgrade):
		"""The logic is calculating the average level of each kind of resource fields, then upgrade 
				   the resource which is the lowest level average value."""

		# Calcuate which field to upgrade
		min = -1
		for field in self.fields:
			if field[0] == to_upgrade and field[1] < 10:
				if min == -1: 
					min = field[1]
					url = field[2]
				if field[1] < min:
					min = field[1]
					url = field[2]  # The URL to upgrade
		if min == -1 : return
		print "[UPGRADE] url = ", url   #DEBUG
		
		# Get build.php page
		self.safeFetch(urlparse.urljoin(self.host, url))
		
		# If food insufficient, then change to upgrade Crop Land first
		if self.contents.find("粮食产量不足: 需要先建造一个农场") >= 0:
			print "[MSG] Food needed, upgrade Crop Land first"
					# Calcuate which field to upgrade
			to_upgrade = FOOD
			min = -1
			for field in self.fields:
				if field[0] == to_upgrade:
					if min == -1: 
						min = field[1]
						url = field[2]
					if field[1] < min:
						min = field[1]
						url = field[2]
			self.safeFetch(urlparse.urljoin(self.host, url))   # Get Crop Land build page
  
		building = [FIELDS_NAMES[to_upgrade][LANG], min, url] 
		self.upgradeBuilding(building)

		self.parseConstructing()
	
	# Parse building page, get upgrade link and upgrade the building
	def upgradeBuilding(self, building):
		self.safeFetch(building[BUILDING_URL])
		try:
			m = re.search('<table class="f10">.+?</div></div></div>', self.contents, re.S)
			block = m.group()
			
			m = re.search('<a href="dorf.+?</a>', block)
			if m: # Able to build, get link
				link_block = m.group()
				n = re.search('".+"', link_block)
				link = n.group()[1:-1]
				print "link = ", link   # DEBUG
				level = building[BUILDING_LEVEL] + 1
				link = urlparse.urljoin(self.host, link)
				print "level = ", level # DEBUG
				if self.verbose: print "[Action] Upgrade %s to level %d" % (building[BUILDING_TITLE], level)
				#print "[DBG] url = ", link
				self.safeFetch(link)
				return True

			else: # Unable to build (Insufficient resources, other constructing in process...)
				# get cause
				m = re.search('<span class="c">.+?</span>', block)
				reason = m.group()[16:-7]
				# get the costs
				costs_str = re.findall('>\d+ ', block)
				costs = [0,0,0,0,0]
				for i in range(len(costs)):
					costs[i] = int(costs_str[i][1:-1])
				#print costs      # DEBUG
				#self.savePage('./data/upgrading.html')
				if self.verbose: 
					print "[MSG] %s unable to build %s. Cost: W:%d C:%d I:%d F:%d E:%d" % \
					(reason, building[BUILDING_TITLE], costs[0], costs[1], costs[2], costs[3], costs[4])
				return False
		except:
			print "[ERR] Parsing building %s failed" % building[BUILDING_TITLE]
			self.savePage('./data/upgrading.html')
			return False
			
	
	# Construct a specific building, or upgrading if already exists
	def build(self, name):
		url = ''
		# Upgrade building if building exists
		for building in self.buildings:
			if building[BUILDING_TITLE] == name:
				print "[MSG] Schedule upgrade %s to level %d" % \
					( building[BUILDING_TITLE], building[BUILDING_LEVEL] + 1)
				return self.upgradeBuilding(building)
		
		# If construction site has not been parsed, parse it
		if len(self.building_options) == 0:
			self.parseConstructionSite()
			
		# Build new if building not exist
		for option in self.building_options:    # Check if the building in building options list
			if option[BUILDING_OPT_TITLE] == name:
				#if self.verbose: print "[MSG] Schedule bulid", option[BUILDING_OPT_TITLE]
				if option[BUILDING_OPT_URL] == None:
					if self.verbose: print "[MSG] Insufficient resource: W:%d C:%d I:%d F:%d E:%d" % \
					(option[BUILDING_OPT_COSTS][WOOD], option[BUILDING_OPT_COSTS][CLAY], \
					option[BUILDING_OPT_COSTS][IRON], option[BUILDING_OPT_COSTS][FOOD], \
					option[BUILDING_OPT_COSTS][EAT])
					return False
				else:
					#print "[DBG] building link %s, start building" % option[BUILDING_OPT_URL]
					if self.verbose: print "[Action] Construct new building %s" % option[BUILDING_OPT_TITLE]
					self.safeFetch(option[BUILDING_OPT_URL])
					return True
		# No building such a building name exist in either upgrading list or new building list
		print "[ERR] building %s not exists" % name
	
	# Upgrade a particular building to a specified level
	def levelBuilding(self, building_title, level):
		current_level = self.getBuildingLevel(building_title)
		if current_level < level:
			if self.build(building_title):
				current_level += 1
				if current_level < level:
					return False  # The building has not reached the expected level yet
				else: # Buliding in construction, we assume it reached the expected level
					return True 
		else: 
			return True     # The bulding reached expected level
	
	def setMain():
		return False
	# Decide to upgrade resource fields, build new building or creat army
	def strategy(self):
		if len(self.constructings) > 0:
			#print "[MSG] Building in processing."
			return
		meanlevels = self.meanLevel()
		# Computing resource fields leven average
		sum = 0
		for meanlevel in meanlevels:
			sum += meanlevel
		mean = float(sum)/len(meanlevels)
		print "[DBG] Strategy: mean = ", mean
		# Schedule action base on mena value
		while True:
			if 2.2 > mean and self.villagename == '新的村庄':
				if not self.levelBuilding('中心大楼',5):break
				if not self.levelBuilding('大使馆',1):break
				if not self.levelBuilding('皇宫',1):break
				if not self.setMain():break
				break;
			elif 2.2<= mean <2.3:
				#print "[DBG] Strategy: Enable gold coins, build wearhouse L1"
				#self.enableGoldCoins()
				if not self.levelBuilding('仓库', 1): break
			elif 2.3<= mean < 2.6:
				#print "[DBG] Strategy: Cave: L1"
				if not self.levelBuilding('仓库', 1): break
				if not self.levelBuilding('山洞', 1): break
			elif 2.6<= mean < 2.7:
				#print "[DBG] Strategy: Cave: L2"
				if not self.levelBuilding('仓库', 1): break
				if not self.levelBuilding('山洞', 2): break
			elif 2.7<= mean < 2.8:
				#print "[DBG] Strategy: Cave: L4, Warehouse L1"
				if not self.levelBuilding('仓库', 1): break
				if not self.levelBuilding('山洞', 4): break
				self.ratio = [90,90,95,60,30]
			elif 2.8<= mean < 2.9:
				#print "[DBG] Strategy: Cave: L6"
				if not self.levelBuilding('仓库', 1): break
				if not self.levelBuilding('山洞', 6): break
			elif 2.9<= mean < 3:
				#print "[DBG] Strategy: Cave: L8"
				if not self.levelBuilding('仓库', 1): break
				if not self.levelBuilding('山洞', 8): break
			elif 3<= mean < 3.1:
				#print "[DBG] Strategy: Cave: L9, CropStock L1"
				if not self.levelBuilding('山洞', 9): break
				if not self.levelBuilding('粮仓', 1): break
			elif 3.1<= mean < 3.2:
				#print "[DBG] Strategy: Cave: L10"
				if not self.levelBuilding('仓库', 1): break
				if not self.levelBuilding('山洞', 10): break
				if not self.levelBuilding('集结点', 1): break
			elif 3.2<= mean < 3.3:
				#print "[DBG] Strategy: Warehouse: L2"
				if not self.levelBuilding('仓库', 2): break
			elif 3.3<= mean < 3.5:
				#print "[DBG] Strategy: TownHall: L2, Cave L11"
				if not self.levelBuilding('中心大楼', 2): break
			elif 3.5<= mean < 4: 
				#print "[DBG] Strategy: Town Hall: L3, Cave L12"
				if not self.levelBuilding('中心大楼', 3): break
			elif 4<= mean < 4.1:
				#print "[DBG] Strategy: Warehouse: L3, Cave L14"
				if not self.levelBuilding('仓库', 3): break
			elif 4.1<= mean < 4.2:
				#print "[DBG] Strategy: CropStock: L1, Cave L15, Town Halll: L4"
				if not self.levelBuilding('粮仓', 2): break
				if not self.levelBuilding('中心大楼', 4): break
			elif 4.2<= mean < 4.3:
				#print "[DBG] Strategy: Warehouse: L4, Cave L16"
				if not self.levelBuilding('仓库', 4): break
			elif 4.4<= mean < 4.5:
				#print "[DBG] Strategy: Cave L16, Cropstock L3, Town Hall: L5"
				if not self.levelBuilding('粮仓', 3): break
				if not self.levelBuilding('中心大楼', 5): break
			elif 4.5<= mean < 4.6:
				#print "[DBG] Strategy: Cave L17"
				if not self.levelBuilding('粮仓', 5): break
				if not self.levelBuilding('中心大楼', 6): break
			elif 4.6<= mean < 4.7:
				#print "[DBG] Strategy: Cave L18"
				if not self.levelBuilding('仓库', 5): break
				if not self.levelBuilding('中心大楼', 7): break
			elif 4.7<= mean < 4.8:
				#print "[DBG] Strategy: Cave L19"
				if not self.levelBuilding('粮仓', 6): break
				if not self.levelBuilding('仓库', 6): break
				if not self.levelBuilding('中心大楼', 8): break
			elif 4.8<= mean < 4.9:
				#print "[DBG] Strategy: Cave L20"
				if not self.levelBuilding('粮仓', 7): break
				if not self.levelBuilding('仓库', 7): break
				if not self.levelBuilding('中心大楼', 9): break
			elif 4.9<= mean < 5.9:
				#print "[DBG] Strategy: Cave L20"
				if not self.levelBuilding('粮仓', 8): break
				if not self.levelBuilding('仓库', 8): break
				if not self.levelBuilding('中心大楼', 10): break
			elif 5.9<= mean < 6.8:
				#print "[DBG] Strategy: Cave L20"
				if not self.levelBuilding('粮仓', 9): break
				if not self.levelBuilding('仓库', 9): break
				if not self.levelBuilding('行宫', 5): break
				if not self.levelBuilding('中心大楼', 11): break
			elif 6.8<= mean < 7.9:
				#print "[DBG] Strategy: Cave L20"
				if not self.levelBuilding('粮仓', 10): break
				if not self.levelBuilding('仓库', 10): break
				if not self.levelBuilding('中心大楼', 12): break
				if not self.levelBuilding('行宫', 10): break
			elif 7.9<= mean < 10:
				#print "[DBG] Strategy: 冲十，"
				if not self.levelBuilding('中心大楼', 13): break
				pass
			elif 10 <= mean:
				self.ratio = [90,90,90,60,30]
				if not self.levelBuilding('中心大楼', 14): break
				if not self.levelBuilding('粮仓', 12): break
				if not self.levelBuilding('仓库', 11): break
				if not self.levelBuilding('中心大楼', 15): break
				if not self.levelBuilding('粮仓', 13): break
				if not self.levelBuilding('仓库', 12): break
				if not self.levelBuilding('中心大楼', 16): break
				if not self.levelBuilding('粮仓', 14): break
				if not self.levelBuilding('仓库', 13): break
				if not self.levelBuilding('中心大楼', 17): break
				if not self.levelBuilding('粮仓', 15): break
				if not self.levelBuilding('仓库', 14): break
				if not self.levelBuilding('中心大楼', 18): break
				if not self.levelBuilding('市场', 15): break
				if not self.levelBuilding('粮仓', 16): break
				if not self.levelBuilding('中心大楼', 19): break
				if not self.levelBuilding('仓库', 15): break
				if not self.levelBuilding('粮仓', 18): break
				if not self.levelBuilding('中心大楼', 20): break
				if not self.levelBuilding('仓库', 16): break
				if not self.levelBuilding('粮仓', 19): break
				if not self.levelBuilding('仓库', 17): break
				if not self.levelBuilding('粮仓', 20): break
				if not self.levelBuilding('仓库', 20): break
				if not self.levelBuilding('市场', 20): break
				if not self.levelBuilding('交易所', 20): break
			if 2.6<= mean < 2.7:
				self.ratio = [80,90,95,60,30]
			elif mean < 2.8:
				self.ratio = [90,90,95,60,30]
			elif mean < 2.9:
				self.ratio = [90,90,95,60,30]
			elif mean < 3.5:
				self.ratio = [90,90,90,60,30]
			elif mean < 4: 
				self.ratio = [95,90,90,70,30]
			elif mean < 4.1:
				self.ratio = [95,100,95,70,30]
			elif mean < 4.3:
				self.ratio = [90,90,95,60,30]
			elif mean < 4.7:
				self.ratio = [90,95,90,60,30]
			else:
				self.ratio = [90,90,90,60,30]
			to_upgrade = self.strategyRatioBased()
			self.upgradeField(to_upgrade)
			break

class Travians:
	'''Maintain multiply accounts in a global strategy perspective. 
		Main Responsibilities:
			Load configure file.
			Assigning proxy for each account.
			Schedule connection time.
			Group attacking strategies.
	'''
	verbose = True
	config_file = ''                # Absoute path of configure file
	accounts = []              # The list of accounts
	using_proxies = []        # A list of in using proxies
	myproxy = None
	isGenHtmlReport = False # Generate HTML report?
	reports = []                    # Reports for each account
	report_file = './report.html'
	cookies_dir = './cookies/'
	z = 0  # Scan map location
	
	def __init__(self):
		self.z = 0
		# Load MyProxy class
		if not self.myproxy: 
			self.myproxy = myproxy.MyProxy()
			
	def usage(self):
		print "Usage:"
		print " Edit travians.cfg before you run this program. "
		print " Writen the username and password of each account in a single line, sepereded by space"
		print " For example: "
		print "  foo bar"
		print "  foo1 bar1"
		print "  ..."

	# Save configure file
	def saveConfig(self):
		if os.path.isfile(self.config):
			os.remove(self.config)
		fobj = open(self.config, 'w')
		fobj.write("# Travians configure file\n")
		fobj.write("# Write each account in a single line, in the format of \"username password\"\n")
		fobj.write("# Comments starts with hash key(#)\n")
		for account in self.accounts:
			line = account[0] + " " + account[1] + " " +  account[2] + "\n"
			fobj.write(line)
		fobj.close()
	
	def loadConfig(self, type=None):
		# Create working directory if not exists
		dir = os.path.abspath(DIR)
		if not os.path.isdir(dir):
			try:
				os.mkdir(dir)
				ok = 1
			except:
				print '[ERR] Cannot mkdir:', dir
				sys.exit()
		
		# Load accounts
		if type=='banned':
			filename = os.path.join(dir, BANNED)
		else:
			filename = os.path.join(dir, CONFIG)
		if not os.path.isfile(filename):
			self.usage() 
			sys.exit()
		self.accounts = []
		for line in open(filename):
			line = line.strip()
			if len(line) == 0: continue # Skip empty line
			if line[0] == '#': continue # Skip comment line
			parts = line.split()
			if len(parts) <> 3: 
				print "[ERR] Error configure file, line: %s" % line
				continue
			
			# Format: username password
			# Assign a proxy(must not in the in use proxy list) for this account
			username, password, host = parts
			self.accounts.append([username, password, host])
		
		if self.verbose: print "[MSG] %d accounts loaded" % len(self.accounts)
		#self.accounts.sort() # sort accounts in the list
		
	# Save report in file
	def saveReports(self):
		header = '''<html><head><title>Travian Gamebot Report</title>
<meta http-equiv="imagetoolbar" content="no">
<meta http-equiv="content-type" content="text/html; charset=UTF-8"></head>
<body>'''
		footer = '</body></html>'
		filename = os.path.join(os.path.abspath(DIR), self.report_file)
		if os.path.isfile(filename):
			os.remove(filename)
		fobj = open(filename, "w")
		fobj.write(header)
		for report in self.reports:
			fobj.write(report)
		fobj.write(footer)
		fobj.close()
	
	def getCookieFilename(self, username, host):
		dir = os.path.abspath(DIR)
		cookies_dir = os.path.join(dir, self.cookies_dir)
		cookies_dir = os.path.normpath(cookies_dir)
		if not os.path.isdir(cookies_dir):
			try:
				os.mkdir(cookies_dir)
				ok = 1
			except:
				print '[ERR] Cannot mkdir:', dir
				sys.exit()
		m=re.findall('http://s([\d|w]+)\.travian\.*',host)
		filename = username + '.cookie' + m[0]
		filename = os.path.join(cookies_dir, filename)
		filename = os.path.normpath(filename)
		return filename


	# Loop every account to upgrading
	def maintain(self):
		# Load accounts
		# FIXME: Following two statements can be deleted in release
		if len(self.accounts) == 0: # Load config is necessary
			self.loadConfig()
		
		logfile = file('travian.log', 'a+')

		#sys.stdout = logfile
		# Padding empty reports
		if self.isGenHtmlReport:
			for i in range(len(self.accounts)):
				self.reports.append('')
		
		loop_count = 1
		while True:
		#if True:
			if len(self.accounts) == 0: # Load config is necessary
				loop_count += 1
				self.loadConfig()
			remains = len(self.accounts)
			outMsg = "[MSG] Loop: %d, %d accounts remaining in this loop" % (loop_count, remains)
			logging.info(outMsg)
			#rint "[MSG] Loop: %d, %d accounts remaining in this loop" % (loop_count, remains)
			a = random.randint(0, remains-1)
			account = self.accounts[a]
			try: # Top Error Control
				username, password, host= account
				#username = "bugzilla";  password = "zillabug"   # DEBUG ONLY
				# Initialize Travian class
				cookie_file = self.getCookieFilename(username, host)
				session = TravianSession(username, password) # DEBUG ONLY, proxy disabled
				#session = TravianSession(username, password, self.myproxy)
				session.host = host
				session.logfile = logfile
				session.cookie_file = cookie_file
				session.curlInit()
				
				# Login
				if not session.login():
					logging.error("Login failed: "+ username + password + session.host)
					self.accounts.remove(account)
					continue    # If login failed, remove and turn to next
				#delete 交易消息
				session.deleteMessage("trade")
				for v in session.villages:
					#test
					#strvillage = '?newdid=187816'
					#if v != strvillage:
					#	continue
					session.village = v
					session.buildings = []
					session.building_options = []
					session.constructings = []
					session.reports = []
					session.resources
					session.fields = []
					session.parseDorf1() # Parse resource status					
					session.parseAttackPage()
					session.parseEnemyVillage() # Parse 对方坐标
					session.parseDorf2() # Parse town page
					#session.parseNews()  # Receive messages/reports if any new
					session.parseProfile()
					session.display() # Print status on console
					session.postRobot() # Post account status to tfen.us
					# Generate HTML report for this account
					if self.isGenHtmlReport:
						index = self.accounts.index(account)
						report = session.genReport()
						self.reports[index] = report
						# Save HTML report
						self.saveReports()
					'''	
					session.testStrategy() # Test Strategy
					session.strategy() # Schedule upgrading/constructing
					'''
					if self.verbose: 
						print "[MSG] Sleep 2 seconds"
					
					time.sleep( 2 )
				logfile.flush()
				self.accounts.remove(account)
				ti = random.randint(2, 60)
				print "[MSG] Sleep", ti,"seconds for account switch!"
				for i in range(ti):
					print '*',
					sys.stdout.flush()
					time.sleep(1)
				print ''
			except KeyboardInterrupt:
				logging.error("[ERR] Error occur")
				logging.error('FAILED '+ str(sys.exc_info( )))
				break #continue
			except: 
				logging.error("[ERR] Error occur")
				logging.error('FAILED '+ str(sys.exc_info()) )
				continue
			finally:
				session.curlClose() # Release curl resources and save cookie file
			#break # DEBUG ONLY, one time only
		

	# Schedule attack, grabbing, assist, resource transactions
	def schedule(self):
		pass
		
	#--------------------------------------------------------------------------
	# Map scan
	def scan(self):
		scanlist = []
		
		# Generate scan list
		corx , cory = [-165,-156]
		rangexy = 30
		for y in xrange(cory - rangexy, cory + rangexy, 7):
			for x in xrange(corx - rangexy, corx + rangexy, 7):
				scanlist.append([x,y])
		while True:
			if len(self.accounts) == 0: # Load config is necessary
				self.loadConfig(type='banned')
			a = random.randint(0, len(self.accounts)-1)
			account = self.accounts[a]
			print "[MSG] %d scan left" % len(scanlist)
			try:
				username, password, host = account
				cookie_file = self.getCookieFilename(username, host)
				#session = TravianSession(username, password, self.myproxy)
				session = TravianSession(username, password) # DEBUG ONLY, proxy disabled
				session.host = host
				session.cookie_file = cookie_file
				session.curlInit()
				# Login
				if not session.login():
					print "Login failed: ", username
					continue    # If login failed, turn to next account
				filename = DIR+'/data/site'+str(int(time.time()))+'.txt'
				session.postfile = open (filename, "a")
				# Parse map
				while True:
					max = len(scanlist)
					if max ==0: break
					i = random.randint(0, max-1)
					#session.parseMap(scanlist[i][0], scanlist[i][1])
					#session.parseMap(52, -136) # DEBUG
					session.parseMapDetail(scanlist[i][0], scanlist[i][1])
					time.sleep( random.randint(2, 4) )
					scanlist.remove(scanlist[i])
					#break # DEBUG ONLY
			except:
				print "[ERR] Error occured during scan (%d|%d)" % \
						(scanlist[i][0], scanlist[i][1])
				print 'FAILED', sys.exc_info( )[:2]
				continue # Jump to next account
			finally:
				if len(scanlist) == 0: 
					break
				else:
					#print "[MSG] sleep random sec", len(scanlist)
					print "[MSG] scan over"
					#time.sleep( random.randint(2, 11-1) )
				break

	#--------------------------------------------------------------------------
	# Map scan
	def scantxt(self):
		scanlist = []
		
		# Generate scan list
		gfile = open ('./data/9t15', "r")
		for l in gfile:
			try:
				w = l.split(',')
				scanlist.append( [int(w[0]), int(w[1]), int(w[2]), int(w[7]) ] )
			except:
				pass
		while True:
			if len(self.accounts) == 0: # Load config is necessary
				self.loadConfig(type='banned')
			a = random.randint(0, len(self.accounts)-1)
			account = self.accounts[a]
			print "[MSG] %d scan left" % len(scanlist)
			#try:
			if True:
				username, password, host = account
				cookie_file = self.getCookieFilename(username, host)
				#session = TravianSession(username, password, self.myproxy)
				session = TravianSession(username, password) # DEBUG ONLY, proxy disabled
				session.host = host
				session.postfile = open ('./data/postGreen.txt', "aw")
				session.cookie_file = cookie_file
				session.curlInit()
				# Login
				if not session.login():
					print "Login failed: ", username , self.host
					continue    # If login failed, turn to next account
				# Parse map
				for t in scanlist:
					session.parseMapGreen(t[0], t[1], t[2], t[3])
			try :
				pass
			except:
				print "[ERR] Error occured during scan (%d|%d)" % \
						(t[0], t[1])
				print 'FAILED', sys.exc_info( )[:2]
				continue # Jump to next account
			finally:
				break
				pass
				#break # DEBUG ONLY

	#--------------------------------------------------------------------------
	# Map scan
	def testCase(self):
		if len(self.accounts) == 0: # Load config is necessary
			self.loadConfig(type='banned')
		a = random.randint(0, len(self.accounts)-1)
		account = self.accounts[a]
		if True:
			username, password, host = account
			cookie_file = self.getCookieFilename(username, host)
		#session = TravianSession(username, password, self.myproxy)
			session = TravianSession(username, password) # DEBUG ONLY, proxy disabled
			session.host = host
			session.cookie_file = cookie_file
			session.curlInit()
		# Login
			if not session.login():
				print "Login failed: ", username
		# Parse map
		session.parseCell2( urlparse.urljoin(session.host, "karte.php?d=334393&c=c2") )
	
	#--------------------------------------------------------------------------
	# Delete trade message
	def deleteTradeMessge(self):
		if len(self.accounts) == 0: # Load config is necessary
			self.loadConfig(type='banned')
		for account in self.accounts:
			username, password, host = account
			cookie_file = self.getCookieFilename(username, host)
			session = TravianSession(username, password) # DEBUG ONLY, proxy disabled
			session.host = host
			session.cookie_file = cookie_file
			session.curlInit()
			# Login
			if not session.login():
				print "Login failed: ", username
			else:
				# Parse map
				session.deleteMessage("trade")
				#session.deleteMessage("attack")
				#session.deleteMessage("support")
				#session.deleteMessage("other")
				
	
if (__name__ == "__main__"):
	logging.basicConfig()
	#	print "test"
	hdlr = logging.FileHandler("trs6.log")
	formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
	formatter.datefmt='%D %T' 
	hdlr.setFormatter(formatter)
	logger = logging.getLogger()
	logger.addHandler(hdlr)
	logger.setLevel(logging.NOTSET)
	#	logging.error('test error')
	#logging.debug('log test')
	#exit()
	travians = Travians()
	#travians.scan()
	#travians.deleteTradeMessge()
	if len(sys.argv) == 1:
		#travians.deleteTradeMessge()
		travians.maintain()
		#travians.scan()
	else:
		for arg in sys.argv:
			if arg.lower() == 'scan':
				travians.scan()
			elif arg.lower() == 'scantxt':
				travians.scantxt()
			elif arg.lower() == 'test':
				travians.testCase()
			elif arg.lower() == 'del':
				travians.deleteTradeMessge()
				
			
